﻿package {


	import de.polygonal.ds.DLinkedList;
	import de.polygonal.ds.DListIterator;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.*;
	
	import flash.geom.Matrix;
	import flash.geom.Transform;
	import flash.text.TextField;
	
	import flash.geom.Point;
	
	import flash.media.Sound;
	
	import flash.utils.Timer;
	
	public class BlockMap extends MovieClip {
		

		public static var BLOCK_WIDTH:int = 45;
		public static var BLOCK_HEIGHT:int = 45;
		public static var BLOCKCOUNT_W:int = 8;
		public static var BLOCKCOUNT_H:int = 8;
		public static var BLOCK_DROP_SPEED:Number = 1200;
		public static var BLOCK_DROP_SPEED_CURRENT:Number = BLOCK_DROP_SPEED;
		
		public static var ROT_BLOCKMAP_SPEED:Number = 200;
		
		private var bBlockEvent:Boolean;
		
		private var willMakePin:Boolean;
		
		var ptBigCheck:Array = [
								[new Point(0,0), new Point(0,0)],
								[new Point(0,1), new Point(1,1)],
								[new Point(0,1), new Point(-1,1)],
								[new Point(0,0), new Point(-1,0)],
								[new Point(0,0), new Point(1,0)]
								];
		var ptBigSwapArray:Array = [
								[new Point(0,0), new Point(0,0), new Point(0,0), new Point(0,0)],
								[new Point(0,0), new Point(1,0), new Point(0,-1), new Point(1,-1)],
								[new Point(0,0), new Point(-1,0), new Point(0,-1), new Point(-1,-1)],
								[new Point(0,-1), new Point(-1,-1), new Point(0,-2), new Point(-1,-2)],
								[new Point(0,-1), new Point(1,-1), new Point(0,-2), new Point(1,-2)]
								];
								
		var ptCheck:Array = [new Point(1, 0), new Point(0, -1), new Point(1, -1)];
		
		private var matTransform:Matrix = new Matrix();
		private var matTemp0:Matrix = new Matrix();
		private var matTemp1:Matrix = new Matrix();
		private var matRot:Matrix = new Matrix();
		private var tempMat:Matrix;
			
		private var BlockArr:Array;	//m_pBlockMap
		private var SaveBlockArr:Array;	//m_pSaveBlockMap
		
		private var RefillBlockArr:Array;
		
		private var RotationToAngle:Number;
		private var RotationAngle:Number;
		private var RotDir:Number;
		
		private var prevMouseX:int;	//RollOver변화를 감지하기 위한 값
		private var prevMouseY:int;
		
		private var loseBlockCnt:int;
		
		public var LeftBigStarCount:int;
		
		public static var currentCombo:int;
		public static const ComboBonus:Array = [1.0, 1.2, 1.5, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 4.9, 5.0];
		
		public static var SCORE:Number;
		
		
		public const PointPinMultiRate:Array = [2,3,4,5,6,6,7,7,8,8,9,9,33,33,55,55,77,77,77,99,99,99];
		public var PointPinBlocks:Array;
		public static var PointPinIndexArray:Array;
		
		private const RATE_TABLE = [1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 3, 3, 3, 3, 2, 1, 1, 2, 3, 4, 4, 3, 2, 1,	1, 2, 3, 4, 4, 3, 2, 1, 1, 2, 3, 3, 3, 3, 2, 1,	1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1];
		
		
		//R G B star stone
		public static var blockColorRate:Array;		
		
		private var isRotating:Boolean = false;
		
		private var fdt:Number = 0.033;
		
		private var BlockLinkCheck:Array;
		
		static public var BlockLinkArr:Array;
		
		private var BlockLinkLevel:Sprite;
		
		
		public var LinkColorBlockList:DLinkedList = new DLinkedList();
		private var CheckBlockList:DLinkedList = new DLinkedList();
		private var TempLinkBlockList:DLinkedList = new DLinkedList();
		
		
		private var MagicTurnFlag:Boolean;
		private var bigStarFlag:Boolean;
		private var EraserBonusFlag:Boolean;
		private var chainBlockFlag:Boolean;
		private var EraserFlag:Array;
		//0 : 왕별클리어뒤 지우개 1개 발생
		//1 : 포인트블록 3개 연속 클리어시
		//2 : 일반클리어시 빅블럭의 개수가 5개 이상이면
		
		private var EraserBlocks:Array //BGR Eraser Blocks in the stage
		
		
		private var bonusState = 0;
		//0: 스몰스타
		//1: 빅블록클리어
		//2: 빈공간회전
		//3: 지우개
		//4: 왕별
		
		public var bonusTimeDelay:int = 14;
		public var BonusTimeArr:Array;
		
		
		private var m_nHighLightBlockPos;
		
		private var pChangeColor;	//스타블럭 변하는 색
		
		public function BlockMap() {
			
			addEventListener(Event.ADDED_TO_STAGE, Init);
			
		}
		
		//
		public function dispose() {
			trace("dispose called");
			
			var i:*;
			
			
			
			try{
			if(stage.hasEventListener(MouseEvent.MOUSE_WHEEL)){
				stage.removeEventListener(MouseEvent.MOUSE_WHEEL, onWheel);
			}
			}catch(e:TypeError) {
				trace("에러1");
			}
			try{
			if (stage.hasEventListener(KeyboardEvent.KEY_DOWN)) {
				stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKey);
			}
			}catch(e:TypeError) {
				trace("에러2");
			}
			
			removeEventListener(CustomEvent.START_BONUS, startBonus);
			removeEventListener(Event.ENTER_FRAME, Update);
			removeEventListener(Event.ENTER_FRAME, Draw);
			removeEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
			removeEventListener(MouseEvent.MOUSE_MOVE, OnMouseMove);
			removeEventListener(MouseEvent.ROLL_OVER, OnMouseMoveIn);
			removeEventListener(MouseEvent.ROLL_OUT, OnMouseMoveOut);
			
			
			
			
			removeEventListener(CustomEvent.ROTATE_LEFT, onRequestRotateLeft);
			removeEventListener(CustomEvent.ROTATE_RIGHT, onRequestRotateRight);
			
			removeEventListener(CustomEvent.KILL, kill);
			
			removeEventListener(Event.ENTER_FRAME, bonusTime);
			
			
			
			
			//블럭의 참조를 가지는 객체를 모두 삭제
			LinkColorBlockList.clear();
			LinkColorBlockList  = null;
			
			
			BlockLinkCheck = null;
			//BlockLinkArr = null;
			
			
			BlockLinkCheck = null;
			
			
			
			for (i = 0; i < RefillBlockArr.length; i++){
				RefillBlockArr[i].dispose();
				RefillBlockArr[i] = null;
			}
			RefillBlockArr = null;
			for (i = 0; i < SaveBlockArr.length; i++){
				SaveBlockArr[i].dispose();
				SaveBlockArr[i] = null;
			}
			SaveBlockArr = null;
			//블럭들 모두 삭제			
			for (i = 0; i < BlockArr.length; i++ ) {
				BlockArr[i].dispose();
				removeChild(BlockArr[i]);
				BlockArr[i] = null;
			}
			BlockArr = null;
			
			try{
			for (var j:int = 0; j < BlockLinkArr.length; j++) {
				
				BlockLinkLevel.removeChild(BlockLinkArr[j].RLink);
				BlockLinkLevel.removeChild(BlockLinkArr[j].DLink);
				
				BlockLinkArr[j].RLink = null;
				BlockLinkArr[j].DLink = null;
				
			}
			
			removeChild(BlockLinkLevel);
			
			}catch (e:ArgumentError) {
				
				trace("에러여기");
			}
			BlockLinkArr = null;
			BlockLinkLevel = null;
			
		}
		
		private function Init(e:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, Init);
			
			PointPinBlocks = [false, false, false];
			PointPinIndexArray = [0,0,0];
			
			willMakePin = true;
			
			stage.addEventListener(MouseEvent.MOUSE_WHEEL, onWheel, false, 0, true);
			
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKey, false, 0, true);
			
			addEventListener(CustomEvent.START_BONUS, startBonus, false, 0, true);
			addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
			addEventListener(Event.ENTER_FRAME, Draw, false, 0, true);
			addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown, false, 0, true);	
			addEventListener(MouseEvent.MOUSE_MOVE, OnMouseMove, false, 0, true);
			addEventListener(MouseEvent.ROLL_OVER, OnMouseMoveIn, false, 0, true);
			addEventListener(MouseEvent.ROLL_OUT, OnMouseMoveOut, false, 0, true);
			
			addEventListener(CustomEvent.ROTATE_LEFT, onRequestRotateLeft, false, 0, true);
			addEventListener(CustomEvent.ROTATE_RIGHT, onRequestRotateRight, false, 0, true);
			
			
			addEventListener(CustomEvent.KILL, kill, true, 0, true);
			
			RotationToAngle = 0;
			RotationAngle = 0;
			RotDir = 0;
			
			bBlockEvent = false;
			
			
			prevMouseX = 0;
			prevMouseY = 0;
			
			loseBlockCnt=0;
			
			LeftBigStarCount = 0;
			
			currentCombo = 0;
			
			SCORE = 0;
			
			MagicTurnFlag = false;
			bigStarFlag = false;
			EraserBonusFlag = false;
			chainBlockFlag = false;
		
			EraserFlag = [true, 0];
			EraserBlocks = [false, false, false];
			
			blockColorRate = [30, 30, 30, 4, 0];	//Point Challenge용 생성 확률
			
			BlockLinkLevel = new Sprite();
			
			BlockLinkArr = new Array(BLOCKCOUNT_W*BLOCKCOUNT_H);
			
			for (var t:int=0; t < BlockLinkArr.length; t++) {
				BlockLinkArr[t] = {RLink:new Link_V(), DLink:new Link_H()};
				BlockLinkLevel.addChild(BlockLinkArr[t].RLink);
				BlockLinkLevel.addChild(BlockLinkArr[t].DLink);
				
				BlockLinkArr[t].RLink.x = int(t%BLOCKCOUNT_W)*BLOCK_WIDTH+42;
				BlockLinkArr[t].RLink.y = int(t/BLOCKCOUNT_H)*BLOCK_HEIGHT;
				
				BlockLinkArr[t].DLink.x = int(t%BLOCKCOUNT_W)*BLOCK_WIDTH;
				BlockLinkArr[t].DLink.y = int(t/BLOCKCOUNT_H)*BLOCK_HEIGHT+42;
			}
			
			addChild(BlockLinkLevel);
			
			var _vtPos:Object = {x:0, y:0};
			BlockArr = new Array(BLOCKCOUNT_W*BLOCKCOUNT_H);
			for (var i:int=0; i < BlockArr.length; i++) {
				BlockArr[i] = new Block();
				//BlockArr[i].Activate();
				BlockArr[i].Deactivate();
				_vtPos.x = int(i%BLOCKCOUNT_W)*BLOCK_WIDTH;
				_vtPos.y = int(i/BLOCKCOUNT_H)*BLOCK_HEIGHT;
				
				BlockArr[i].SetPos(_vtPos);
				BlockArr[i].SetLinkBlock(BlockLinkArr[i].RLink, BlockLinkArr[i].DLink);
				BlockArr[i].Index = i;
				BlockArr[i].DrawLink();
				addChild(BlockArr[i]);
			}
			
			RefillBlockArr = new Array(BLOCKCOUNT_W);
			
			for(var j:int=0; j < BLOCKCOUNT_W; j++){
				RefillBlockArr[j] = new Block();
			}
			
			SaveBlockArr = new Array(BLOCKCOUNT_W * BLOCKCOUNT_H);
			for(var k:int=0; k < SaveBlockArr.length; k++){
				SaveBlockArr[k] = new Block();
			}
			
			BlockLinkCheck = new Array(BLOCKCOUNT_W * BLOCKCOUNT_H);
			
		}
		
		public function blockEvent(){
			//마우스 입력 막기
			trace("blockEvent called");
			
			bBlockEvent = true;
			
			removeEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
			removeEventListener(MouseEvent.MOUSE_MOVE, OnMouseMove);
			removeEventListener(MouseEvent.ROLL_OVER, OnMouseMoveIn);
			removeEventListener(MouseEvent.ROLL_OUT, OnMouseMoveOut);
			stage.removeEventListener(MouseEvent.MOUSE_WHEEL, onWheel);
			
			//stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKey);
			
			
		}
		
		
		public function startBonus(e:CustomEvent){
			trace("BlockMap startBonus called");
			
			
			
			addEventListener(Event.ENTER_FRAME, bonusTime, false, 0, true);
			
			
			
			return;
		}
		private function bonusTime(e:Event){
			//딜레이 주기
			if(bonusTimeDelay > 0){
				bonusTimeDelay--;
				return;
			}else if(bonusTimeDelay == 0){
				bonusTimeDelay = 14;
			}
			
			refreshBonusTimeArray();
			
			
			if(BonusTimeArr[0][0] != null){	//0: 스몰스타
				//BonusTimeArr[0][0]
				
				OnMouseDown(new MouseEvent(MouseEvent.MOUSE_DOWN), BonusTimeArr[0][0].x+10, BonusTimeArr[0][0].y+10);
				//딜레이 타이머 넣기
				return;
			}else if(BonusTimeArr[1][0] != null){	//1: 빅블록클리어
				//BonusTimeArr[1][0]
				
				OnMouseDown(new MouseEvent(MouseEvent.MOUSE_DOWN), BonusTimeArr[1][0].x+10, BonusTimeArr[1][0].y+10);
				return;
			}else if(BonusTimeArr[2][0] != null){	//2: 빈공간회전
				//BonusTimeArr[2][0]
				onWheel(new MouseEvent(MouseEvent.MOUSE_WHEEL), true);
				return;
			}else if(BonusTimeArr[3][0] != null){	//3: 지우개
				//BonusTimeArr[3][0]
				OnMouseDown(new MouseEvent(MouseEvent.MOUSE_DOWN), BonusTimeArr[3][0].x+10, BonusTimeArr[3][0].y+10);
				return;
			}else if(BonusTimeArr[4][0] != null){	//4: 왕별
				//BonusTimeArr[4][0]
				OnMouseDown(new MouseEvent(MouseEvent.MOUSE_DOWN), BonusTimeArr[4][0].x+10, BonusTimeArr[4][0].y+10);
				return;
			}
			//점수 띠리릭 올라가는 속도 변화
			
			
			refreshBonusTimeArray();
			
			
			if(BonusTimeArr[0][0] != null || BonusTimeArr[1][0] != null || BonusTimeArr[2][0] != null || BonusTimeArr[3][0] != null || BonusTimeArr[4][0] != null){
				return;
			}
			
			
			
			trace("보너스타임 끝");
			removeEventListener(Event.ENTER_FRAME, bonusTime);
			
			dispatchEvent(new CustomEvent(CustomEvent.BONUS_OVER));
			
		}
		
		
		private function refreshBonusTimeArray(){
			BonusTimeArr = [
							[],
							[],
							[],
							[],
							[]
							];
			
			for (var i:int = 0; i < BlockArr.length; i++) {
				//빅스타의 더미블럭이 포함됨. 더미블럭은 안넣기
				if(BlockArr[i].GetBigBlockType() == 0 && BlockArr[i].GetBlockColor() == 3 && !BlockArr[i].IsDummyBlock() && BlockArr[i].IsActivate()){
					BonusTimeArr[0].push(BlockArr[i]);
					
					trace("3 is Star", BlockArr[i].GetBlockColor());
					
				}
				if(BlockArr[i].GetBigBlockType() != 0 && BlockArr[i].GetBlockColor() != 3){	//빅블럭이고 스타가 아니면
					BonusTimeArr[1].push(BlockArr[i]);
				}
				if(!BlockArr[i].IsActivate()){
					BonusTimeArr[2].push(BlockArr[i]);
				}
				if(BlockArr[i].GetEraserBlock()){
					BonusTimeArr[3].push(BlockArr[i]);
				}
				if(BlockArr[i].GetBigBlockType() != 0 && BlockArr[i].GetBlockColor() == 3){	//빅스타면
					BonusTimeArr[4].push(BlockArr[i]);
					
				}
			}
			
			trace("BonusTimeArr", BonusTimeArr.join("*\n"));
			
		}
		
		private function onKey(e:KeyboardEvent) :void{
			//trace("onKey ", Menu_InGame.isPaused);
			
			//Pause시가 아니라, Menu_Pause가 나왔을 경우... 
			//Pause시는 다른 경우에도 됨. (시작할때라든지)
			
			//ESC로 Pause창 닫기, Q로 메인으로 가기
			/*if (Menu_InGame.isPaused) {
				switch(e.keyCode) {
					case 27:	//ESC
					Menu_Pause.menuPause.onClickResume();
					break;
					case 81:	//Q
					Menu_Pause.menuPause.onClickQuit();
					break;
				}
				return;
			}*/
			
			if (Menu_InGame.gameOver) return;
			
			if(e.keyCode == 32){	//SPACE
				//MakeEraserBlock();
			}
			
			switch(e.keyCode) {
				case 87:	//W
				if(Menu_InGame.GameTime > 0){
					dispatchEvent(new CustomEvent(CustomEvent.ROTATE_LEFT));
				}
				break;
				case 69:	//E
				if(Menu_InGame.GameTime > 0){
					dispatchEvent(new CustomEvent(CustomEvent.ROTATE_RIGHT));
				}
				break;
				case 82:	//R
				dispatchEvent(new NavigationEvent(NavigationEvent.RESTART, null, null));
				break;
				case 27:	//ESC
				if(Menu_InGame.GameTime > 0){
					dispatchEvent(new NavigationEvent(NavigationEvent.PAUSE, null, null));
				}
				//PAUSE는 Menu_Pause 창을 보여주라는 요청
				//Menu_Pause 창을 닫아라는 요청
				//Menu_Pause 
				break;
				case 81:	//Q
				if(Menu_InGame.GameTime > 0){
					dispatchEvent(new NavigationEvent(NavigationEvent.REQUEST_QUIT, null, null));
				}
				break;
			}
			
			
		}
		
		private function onRequestRotateLeft(e:CustomEvent) {
			Rotation( -1);
		}
		private function onRequestRotateRight(e:CustomEvent) {
			Rotation(1);
		}
		
		
		public function onWheel(e:MouseEvent, _bonusTime:Boolean = false):void{
			trace("onWheel called", _bonusTime);
			
			
			//if(IsBlockMoving()) return;
			if(isRotating == true) return;
			
			//내려가는 중에 돌릴 수 있음 - 안되게
			
			
			
			//trace("IsBlockMoving " + IsBlockMoving());
			if(IsBlockMovingRotation()) return;
			
			
			if(_bonusTime){
				var ran = Math.floor(Math.random()*2);
				if(ran == 0){
					Rotation(1);
				}else if(ran == 1){
					Rotation(-1);
				}
			}else{
				if(e.delta < 0){
					Rotation(1);
				}else if(e.delta > 0){
					Rotation(-1);
				}
			}
		}
		
		private function RefillLine():Boolean{
			
			var pBlock:Block;
			var pBlock1:Block;
			var bReturn:Boolean = false;
			
			var _vtPos = {x:0, y:0};
			
			for(var i:int=0; i < BLOCKCOUNT_W; i++){
				pBlock = BlockArr[i];
				if(!pBlock.IsActivate()){
					_vtPos.x = (i) * BLOCK_WIDTH;
					_vtPos.y = (-1) * BLOCK_HEIGHT;
					
					pBlock1 = RefillBlockArr[i];
					pBlock.SetPos(_vtPos);
					
					_vtPos.y += BLOCK_HEIGHT;
					
					//BLOCK_DROP_SPEED_CURRENT??
					pBlock.MoveToVertical(_vtPos.y, BLOCK_DROP_SPEED_CURRENT);
					pBlock.SetBlockColor(pBlock1.GetBlockColor());
					pBlock.SetDummyBlock(false);
					pBlock.SetPinBlock(false);
					pBlock.SetBigBlockType(0);
					pBlock.SetRollOut();
					pBlock.Activate();
					bReturn = true;
					pBlock1.SetBlockColor(MakeRandomBlock());
				}
			}
			return bReturn;
		}
		
		public function MakeRandomBlock():int{
			try{
			var randomTotal:Number = blockColorRate[0] + blockColorRate[1] + blockColorRate[2] + blockColorRate[3] + blockColorRate[4];
			
			var randomVar = int(Math.random()*randomTotal);
			
			var returnVar:int;
			
			if(0 <= randomVar && randomVar < blockColorRate[0]){
				//R
				returnVar = 0;
			}else if(blockColorRate[0] <= randomVar && randomVar < (blockColorRate[0]+blockColorRate[1])){
				//G
				returnVar = 1;
			}else if(blockColorRate[0]+blockColorRate[1] <= randomVar && randomVar < (blockColorRate[0]+blockColorRate[1]+blockColorRate[2])){
				//B
				returnVar = 2;
			}else if(blockColorRate[0]+blockColorRate[1]+blockColorRate[2] <= randomVar && randomVar < (blockColorRate[0]+blockColorRate[1]+blockColorRate[2]+blockColorRate[3])){
				//star
				returnVar = 3;
			}else if(blockColorRate[0]+blockColorRate[1]+blockColorRate[2]+blockColorRate[3] <= randomVar && randomVar < (blockColorRate[0]+blockColorRate[1]+blockColorRate[2]+blockColorRate[3]+blockColorRate[4])){
				//stone
				returnVar = 4;
			}
			}catch (e:TypeError) {
				trace("Error2");
				trace(MovieClip(this.root).currentFrame);
				return 0;
			}
			
			return returnVar;
		}
		
		private function Update(e:Event):void{
			
			
			
			for(var i:int=0; i<BLOCKCOUNT_W * BLOCKCOUNT_H;i++){
				BlockArr[i].Update();
				
				//일단 link지워줌
				//BlockArr[i].SetRightHand(false);
				//BlockArr[i].SetBottomHand(false);
				//BlockArr[i].DrawLink();
			}
			
			
			if(UpdateRotation(fdt)){
				return;
			}
			
			
			//블럭이 리필중이면 return
			if(RefillLine()){
				return;
			}
			
			//블럭이 움직이고 있으면 return
			if(IsBlockMoving()){
				return;
			}
			
			//블럭이 떨어지고 있으면 return
			if(CheckFallDown()){
				return;
			}
			
			//ProcessLeftBigStar
			if(LeftBigStarCount > 0)
			{
				
				ClearAllMap();
				return;
				
			}
			
			MakeBigBlock();
			
			CheckLinkedBlockList();
			
			//여기서 하지 말기 - 클릭하고 나서
			
			//Point Challenge면 각 색 3개의 블럭을 SetPinBlock
			if(willMakePin){
				MakePinBlock();
				willMakePin = false;
				
			}
			
			if(EraserFlag[0] == true){
				MakeEraserBlock();
				EraserFlag[0] = false;
			}	
			
			
			//여기서 EraserBlock, PinBlock등 나와야 할듯.
			
			
			//블럭이 내려오는 중에는 체크안해야함
			//여기서 체크를 안해도 Draw에서 호출이 되기땜에...
			
			
			
			//MagicTurnFlag = true;	//매직블럭 available
			//trace("Update End");
		}
		
		private function Draw(e:Event):void{
			
			//var matTransform:Matrix = new Matrix(0,0,0,0,this.x, this.y);
			
			matTransform.identity();
			matTemp0.identity();
			matTemp1.identity();
			matRot.identity();
			
			
			
			matTemp0.translate(-BLOCKCOUNT_W*BLOCK_WIDTH/2, -BLOCKCOUNT_H*BLOCK_HEIGHT/2);
			matRot.rotate(RotationAngle);
			matTemp1.translate(BLOCKCOUNT_W*BLOCK_WIDTH/2, BLOCKCOUNT_H*BLOCK_HEIGHT/2);
			
			
			tempMat = MultiMat(matTemp0, matRot);
			
			matTemp0 = MultiMat(tempMat, matTemp1);
			//matTransform.translate(this.x, this.y);
			matTransform = MultiMat(matTemp0, matTransform);
			
			for(var i:int=0; i<BLOCKCOUNT_W * BLOCKCOUNT_H;i++){
				if(BlockArr[i].IsActivate()){
					BlockArr[i].Draw(matTransform);
					
					
				}
			}
			
		}
		
		
		public function MakePinBlock(){
			
			//trace("PointPinBlocks[0]", PointPinBlocks[0]);
//			trace("PointPinBlocks[1]", PointPinBlocks[1]);
//			trace("PointPinBlocks[2]", PointPinBlocks[2]);
			
			if(PointPinBlocks[0] && PointPinBlocks[1] && PointPinBlocks[2]){
				
				//trace("핀블럭이 모두 있음 - 리턴");
				
				return;
			}
			
			
			//범위 내에 있는 Red블럭을 Red Pin 블럭으로
			var bBlocks = [[],[],[],[]];
			var gBlocks = [[],[],[],[]];
			var rBlocks = [[],[],[],[]];
			
			var bBlocksIs:Boolean = false;
			var gBlocksIs:Boolean = false;
			var rBlocksIs:Boolean = false;
			
			for(var i:int=0; i<BLOCKCOUNT_W * BLOCKCOUNT_H;i++){				
				if(BlockArr[i].IsActivate()){
					if(BlockArr[i].GetBigBlockType() == 0){
						if(!BlockArr[i].IsDummyBlock()){
							if(!BlockArr[i].GetEraserBlock()){								
								if(!BlockArr[i].IsPinBlock()){
									switch(BlockArr[i].GetBlockColor()){
										case 0:
										//bBlocks.push(BlockArr[i]);
										bBlocks[RATE_TABLE[i] - 1].push(BlockArr[i]);
										bBlocksIs = true;
										break;
										case 1:
										//gBlocks.push(BlockArr[i]);
										gBlocks[RATE_TABLE[i] - 1].push(BlockArr[i]);
										gBlocksIs = true;
										break;
										case 2:
										//rBlocks.push(BlockArr[i]);
										rBlocks[RATE_TABLE[i] - 1].push(BlockArr[i]);
										rBlocksIs = true;
										break;
									}
								}
							}
						}
					}
				}
			}
			
			trace("rBlocks", rBlocks);
			trace("gBlocks", gBlocks);
			trace("bBlocks", bBlocks);
			
			//if ( && PointPinBlocks[1] && PointPinBlocks[2]) 
			
			
			//bBlock을 만들어야 되는데 그 블럭이 없으면 다음블럭 
			if ((!bBlocksIs && !PointPinBlocks[0]) && (!gBlocksIs && !PointPinBlocks[1]) && (!rBlocksIs && PointPinBlocks[2])) {
				//trace("블럭이 없음 - return");
				
				return;
			}
			
			
			var rateSumB =[0,0,0,0];
			var rateSumG =[0,0,0,0];
			var rateSumR =[0,0,0,0];
			
			
			//적절한 위치에 포인트핀블럭을 만든다.
			var comboPlus:int = 0;
			trace("Pin: currentCombo", currentCombo);
			
			if(currentCombo == 1 || currentCombo == 2){
				comboPlus = 1;
			}else if(2 < currentCombo && currentCombo <= 4){
				comboPlus = 2;
			}else if(4 < currentCombo && currentCombo <= 6){
				comboPlus = 3;
			}else if(6 < currentCombo && currentCombo <= 9){
				comboPlus = 4;
			}else if(9 < currentCombo && currentCombo <= 13){
				comboPlus = 5;
			}else if(13 < currentCombo && currentCombo <= 1000){
				comboPlus = 6;
			}
			
			if(bigStarFlag){
				comboPlus = 1;
				bigStarFlag = false;
			}
			if(EraserBonusFlag){
				comboPlus = 1;
				EraserBonusFlag = false;
			}
			//지우개를 쓰면 ++
			
			//이 때, 파라미터 값에 따라 핀블럭의 index를 증가시켜준다. 
			//index값은 게임이 끝날때까지 계속 이어진다.
			
			
			
			trace("bf");
			
			for(var j:int=0; j < 4; j++){
				trace(j);
				
				for(var k in bBlocks[j]){
					rateSumB[j] += bBlocks[j][k].Index * RATE_TABLE[bBlocks[j][k].Index];
				}
				for(var p in gBlocks[j]){
					rateSumG[j] += gBlocks[j][p].Index * RATE_TABLE[gBlocks[j][p].Index];
				}
				for(var t in rBlocks[j]){
					rateSumR[j] += rBlocks[j][t].Index * RATE_TABLE[rBlocks[j][t].Index];
				}
			}
			trace("ok");
			
			//trace("bBlocks candidate ", bBlocks);
			//trace("gBlocks candidate ", gBlocks);
			//trace("rBlocks candidate ", rBlocks);
			trace("rateSumB", rateSumB);
			trace("rateSumG", rateSumG);
			trace("rateSumR", rateSumR);
			
			
			var rB = int(Math.random() * (rateSumB[0] + rateSumB[1] + rateSumB[2]));
			var rG = int(Math.random() * (rateSumG[0] + rateSumG[1] + rateSumG[2]));
			var rR = int(Math.random() * (rateSumR[0] + rateSumR[1] + rateSumR[2]));
			
			trace("rB : " + rB);
			trace("rG : " + rG);
			trace("rR : " + rR);
			
			var returnB:Block;
			var returnG:Block;
			var returnR:Block;
			
			//Blue 핀블럭이 없으면
			trace("PointPinBlocks[0]", PointPinBlocks[0]);
			trace("bBlocksIs", bBlocksIs);
			if (PointPinBlocks[0] == false && bBlocksIs) {
				
				PointPinIndexArray[0] += comboPlus;
				
				
				if(PointPinIndexArray[0] >= PointPinMultiRate.length){
					PointPinIndexArray[0] = PointPinMultiRate.length-1;
				}
				
				//Debug Log : 0 < 으로 해서 rB가 0일 경우를 놓치고 있었음
				if (0 <= rB && rB <= rateSumB[0]) {
					var r1 = int(Math.random() * bBlocks[0].length);
					trace("r1", r1)
					returnB = bBlocks[0][r1];
					
				}else if (rateSumB[0] < rB && rB <= rateSumB[0] + rateSumB[1]) {
					var r2 = int(Math.random() * bBlocks[1].length);
					trace("r2", r2)
					
					returnB = bBlocks[1][r2];
				}else if (rateSumB[0] + rateSumB[1] < rB && rB <= rateSumB[0] + rateSumB[1] + rateSumB[2]) {
					var r3 = int(Math.random() * bBlocks[2].length);
					trace("r3", r3)
					
					returnB = bBlocks[2][r3];
				}else if (rateSumB[0] + rateSumB[1] + rateSumB[2] < rB && rB <= rateSumB[0] + rateSumB[1] + rateSumB[2] + rateSumB[3]) {
					var r4 = int(Math.random() * bBlocks[3].length);
					trace("r4", r4)
					
					returnB = bBlocks[3][r4];
				}
				
				PointPinBlocks[0] = true;
				
				if (returnB == null) return;
				
				returnB.SetPinBlock(true);
				returnB.PinEffect();
				
				
			}
			
			if(PointPinBlocks[1] == false && gBlocksIs){
				PointPinIndexArray[1] += comboPlus;
				
				if(PointPinIndexArray[1] >= PointPinMultiRate.length){
					PointPinIndexArray[1] = PointPinMultiRate.length-1;
				}
				
				if(0 <= rG && rG <= rateSumG[0]){
					returnG = gBlocks[0][int(Math.random()*gBlocks[0].length)]
				}else if(rateSumG[0] < rG && rG <= rateSumG[0]+rateSumG[1]){
					returnG = gBlocks[1][int(Math.random()*gBlocks[1].length)]
				}else if(rateSumG[0]+rateSumG[1] < rG && rG <= rateSumG[0]+rateSumG[1]+rateSumG[2]){
					returnG = gBlocks[2][int(Math.random()*gBlocks[2].length)]
				}else if(rateSumG[0]+rateSumG[1]+rateSumG[2] < rG && rG <= rateSumG[0]+rateSumG[1]+rateSumG[2]+rateSumG[3]){
					returnG = gBlocks[3][int(Math.random()*gBlocks[3].length)]
				}
				
				PointPinBlocks[1] = true;
				
				if (returnG == null) return;
				
				returnG.SetPinBlock(true);
				returnG.PinEffect();
			}
			if(PointPinBlocks[2] == false && rBlocksIs){
				PointPinIndexArray[2] += comboPlus;
				
				if(PointPinIndexArray[2] >= PointPinMultiRate.length){
					PointPinIndexArray[2] = PointPinMultiRate.length-1;
				}
				
				if(0 <= rR && rR <= rateSumR[0]){
					returnR = rBlocks[0][int(Math.random()*rBlocks[0].length)]
				}else if(rateSumR[0] < rR && rR <= rateSumR[0]+rateSumR[1]){
					returnR = rBlocks[1][int(Math.random()*rBlocks[1].length)]
				}else if(rateSumR[0]+rateSumR[1] < rR && rR <= rateSumR[0]+rateSumR[1]+rateSumR[2]){
					returnR = rBlocks[2][int(Math.random()*rBlocks[2].length)]
				}else if(rateSumR[0]+rateSumR[1]+rateSumR[2] < rR && rR <= rateSumR[0]+rateSumR[1]+rateSumR[2]+rateSumR[3]){
					returnR = rBlocks[3][int(Math.random()*rBlocks[3].length)]
				}
				
				
				PointPinBlocks[2] = true;
				
				if (returnR == null) return;
				
				returnR.SetPinBlock(true);
				returnR.PinEffect();
				
			}
			
		}
		
		public function MakeEraserBlock(){
			trace("MakeEraserBlock called");
			/*private var EraserFlag:Array = [false, 0];
			//0 : 왕별클리어뒤 지우개 1개 발생
			//1 : 포인트블록 3개 연속 클리어시
			//2 : 일반클리어시 빅블럭의 개수가 5개 이상이면		
			private var EraserBlocks:Array = [false, false, false];		//BGR Eraser Blocks in the stage
			*/
			var returnBlock;
			
			var bBlocks = [];
			var gBlocks = [];
			var rBlocks = [];
			
			for(var i:int=0; i<BLOCKCOUNT_W * BLOCKCOUNT_H;i++){				
				if(BlockArr[i].IsActivate()){
					if(BlockArr[i].GetBigBlockType() == 0){
						if(!BlockArr[i].IsDummyBlock()){
							if(!BlockArr[i].GetEraserBlock()){
								if(!BlockArr[i].IsPinBlock()){
									switch(BlockArr[i].GetBlockColor()){
										case 0:
										bBlocks.push(BlockArr[i]);
										break;
										case 1:
										gBlocks.push(BlockArr[i]);
										break;
										case 2:
										rBlocks.push(BlockArr[i]);
										break;
									}
								}
							}
						}
					}
				}
			}
			
			if (bBlocks.length == 0 && !EraserBlocks[0]) {
				return;
			}
			if (gBlocks.length == 0 && !EraserBlocks[1]) {
				return;
			}
			if (rBlocks.length == 0 && !EraserBlocks[2]) {
				return;
			}
			
			var full:Boolean = false;
			if(EraserBlocks[0] && EraserBlocks[1] && EraserBlocks[2]){
				full = true;
				
			}
			
			if(!full){
				trace("없는거 선택");
				//없는거 선택
				switch(int(Math.random()*3)){
					case 0:
					if(EraserBlocks[0]) {
						trace("재귀 G");
						MakeEraserBlock();
						return;
					}
					returnBlock = bBlocks[int(Math.random()*bBlocks.length)];
					EraserBlocks[0] = true;
					trace("재귀 G 이후");
					break;
					case 1:
					if(EraserBlocks[1]) {
						trace("재귀 B");
						MakeEraserBlock();
						return;
					}
					returnBlock = gBlocks[int(Math.random()*gBlocks.length)];
					EraserBlocks[1] = true;
					trace("재귀 B 이후");
					break;
					case 2:
					if(EraserBlocks[2]) {
						trace("재귀 R");
						MakeEraserBlock();
						return;
					}
					returnBlock = rBlocks[int(Math.random()*rBlocks.length)];
					EraserBlocks[2] = true;
					trace("재귀 R 이후");
					break;
				}
			}else{
				trace("아무거나 하나");
				//아무거나 하나
				switch(int(Math.random()*3)){
					case 0:
					returnBlock = bBlocks[int(Math.random()*bBlocks.length)];
					EraserBlocks[0] = true;
					break;
					case 1:
					returnBlock = gBlocks[int(Math.random()*gBlocks.length)];
					EraserBlocks[1] = true;
					break;
					case 2:
					returnBlock = rBlocks[int(Math.random()*rBlocks.length)];
					EraserBlocks[2] = true;
					break;
				}
			}
			returnBlock.SetEraserBlock(true);
			returnBlock.EraserEffect();
			Clickr.snd_EraseBlock.play();
			
			
			return returnBlock;			
		}
		
		
		
		private function UpdateRotation(_fdt:Number):Boolean{
			
			
			var _fdt = 0.0005;		//Rotation Speed
			
			var Rot:Number;
			if(RotationToAngle > 0){
				Rot = CalcRotationAngleFactor(RotationAngle, RotationToAngle);
				RotationAngle += _fdt * Rot;
				if(RotationToAngle < RotationAngle){
					RotationAngle = 0;
					RotationToAngle = 0;
					RotationBlockMap();	//진회전
					
				}
				isRotating = true;
			}else if(RotationToAngle < 0){
				Rot = CalcRotationAngleFactor(RotationAngle, RotationToAngle);
				RotationAngle -= _fdt * Rot;
				if(RotationToAngle > RotationAngle){
					RotationAngle = 0;
					RotationToAngle = 0;
					RotationBlockMap();	//진회전
				}
				isRotating = true;
				
			}else{
				isRotating = false;
				return false;
			}
			
			for(var i:int=0; i < BLOCKCOUNT_W * BLOCKCOUNT_H; i++){
				BlockArr[i].SetRotation(-RotationAngle);
				BlockArr[i].ResetPrevDrawInfo();
			}
			
			
			
			
			return true;
		}
		
		
		private function Rotation(nDir:int):void{
			if (IsBlockMovingRotation()) return;
			
			if(IsBlockMoving()) return;
			
			for(var i:int=0; i<BLOCKCOUNT_W * BLOCKCOUNT_H;i++){
				BlockArr[i].SetRightHand(false);
				BlockArr[i].SetBottomHand(false);
				BlockArr[i].DrawLink();
			}
			
			Clickr.snd_Rotate.play();
			trace("회전");
			if(IsBlockMoving()) return;
			
			RotDir = nDir;
			
			RotationToAngle = RotDir * Math.PI / 2;
			RotationAngle = 0;
			
			MagicTurnFlag = true;
			chainBlockFlag = false;
		}

		private function RotationBlockMap():void{
			
			var vtPos = {x:0, y:0};
			
			var nBlockType:int;
		
			var nSrcBlockArray:int;
			var nDestBlockArray:int;
		
			//현재 블럭 배열을 그대로 저장후
			for(var k:int = 0 ; k < BLOCKCOUNT_W * BLOCKCOUNT_H ; k ++)
			{
				CopyBlock(SaveBlockArr[k], BlockArr[k]);
			}
		
			//회전 위치에 알맞게 돌려준다.
			for(var i:int = 0 ; i < BLOCKCOUNT_W ; i ++)
			{
				for(var j:int = 0 ; j < BLOCKCOUNT_H ; j ++)
				{
					nSrcBlockArray = i + j * BLOCKCOUNT_W;
		
					if(RotDir == 1)
						nDestBlockArray = j + (BLOCKCOUNT_W - i - 1) * BLOCKCOUNT_W;
					if(RotDir == -1)
						nDestBlockArray = (BLOCKCOUNT_W - j - 1) + (i) * BLOCKCOUNT_W;
		
					CopyBlock(BlockArr[nSrcBlockArray], SaveBlockArr[nDestBlockArray]);
					
					
					
					if(BlockArr[nSrcBlockArray].IsPinBlock())
						BlockArr[nSrcBlockArray].DrawPin();
		
					vtPos.x = i * BLOCK_WIDTH;
					vtPos.y = j * BLOCK_HEIGHT;
					BlockArr[nSrcBlockArray].SetPos(vtPos);
					nBlockType = BlockArr[nSrcBlockArray].GetBigBlockType();
					
					//Big block Type이 0이 아닐경우 알맞게 회전 시켜준다.
					if(nBlockType > 0)
					{
						nBlockType = (((nBlockType - 1 + RotDir + 5 - 1)) % (5 - 1)) + 1;
						BlockArr[nSrcBlockArray].SetBigBlockType(nBlockType);
					}
				}
			}
		
			RotDir = 0;
			
		}
		
		private function CopyBlock(pDest:Block, pSrc:Block):void{
			if(pSrc.IsActivate()){
				pDest.Activate();
			}else{
				pDest.Deactivate();
			}
			pDest.SetBlockColor(pSrc.GetBlockColor());
			pDest.SetBigBlockType(pSrc.GetBigBlockType());
			pDest.SetDummyBlock(pSrc.IsDummyBlock());
			pDest.SetRotation(pSrc.GetRotation());
			pDest.SetMagicBlock(pSrc.GetMagicBlock());
			pDest.SetPinBlock(pSrc.IsPinBlock());
			pDest.SetChainBlock(pSrc.GetChainBlock());
			pDest.SetEraserBlock(pSrc.GetEraserBlock());
			
//			if(pSrc.IsRollOver())
//				pDest.SetRollOver();
//			else
				pDest.SetRollOut();
				
		}
		
		private function IsBlockMovingRotation():Boolean{
			if(RotDir) return true;
			if(RotationToAngle) return true;

			return IsBlockMoving();
		}
		
		private function IsBlockMoving():Boolean{
			
			var pBlock:Block;
			
			for(var i:int=0; i<BLOCKCOUNT_W;i++){
				for(var j:int=BLOCKCOUNT_H; j>0; j--){
					
					pBlock = BlockArr[i + (j-1) * BLOCKCOUNT_W];
					
					//어느 한 블럭이라도 이동중이면 true
					if(pBlock.IsActivate()){
						if(pBlock.IsMoved()){
							return true;
						}
					}
				}
			}
			
			return false;
		}
		
		private function CalcRotationAngleFactor(fRot:Number, fMaxRot:Number):Number{
			return Math.sin((0.5 + fRot / fMaxRot * 0.48) * Math.PI ) * 1.5 * Math.PI / 2 * ROT_BLOCKMAP_SPEED;
		}
				
		private function CheckFallDown():Boolean{
			
			var upperBlock:Block;
			var lowerBlock:Block;
			var pBlock2:Block;
			//bReturn을 쓰는 것과 그냥 바로 return하는 것과 다름*************
			var bReturn:Boolean = false;
			
			
			
			for(var i:int=0; i<BLOCKCOUNT_W;i++){
				//맨 아랫줄은 검사 안하기 떔에 -1 빼기
				for(var j:int=BLOCKCOUNT_H-1; j>0; j--){
					
					//upperBlock = pBlock1;
					//lowerBlock = pBlock;					
					upperBlock = BlockArr[i + (j-1)*BLOCKCOUNT_W];
					lowerBlock = BlockArr[i + j*BLOCKCOUNT_W];
					
					if(upperBlock.IsDummyBlock()) { 
					
					}else if(upperBlock.GetBigBlockType() == 0){
						//아래 블럭이 없으면
						if(!lowerBlock.IsActivate() && upperBlock.IsActivate()){
							
							if(upperBlock.IsPinBlock())
							   continue;
							   
							Swap(i+j*BLOCKCOUNT_W, i+(j-1)*BLOCKCOUNT_W);
							bReturn = true;
							
						}
					}else{
						var nType:int = upperBlock.GetBigBlockType();
						
						//if(upperBlock.IsPinBlock() || lowerBlock.IsPinBlock()) continue;
						
						lowerBlock = GetBlock(i + ptBigCheck[nType][0].x, j + ptBigCheck[nType][0].y);
						pBlock2 = GetBlock(i + ptBigCheck[nType][1].x, j + ptBigCheck[nType][1].y);
						if(pBlock2 && lowerBlock){
							if(!lowerBlock.IsActivate() && upperBlock.IsActivate()){
							   
								if(!pBlock2.IsActivate()){
									for(var k:int=0; k < 4; k++){
										Swap(i + ptBigSwapArray[nType][k].x + (j + ptBigSwapArray[nType][k].y) * BLOCKCOUNT_W, i + ptBigSwapArray[nType][k].x + (j + ptBigSwapArray[nType][k].y + 1) * BLOCKCOUNT_W, BLOCK_DROP_SPEED_CURRENT);
									}
									bReturn = true;
								}
							}
						}
					}
				}
			}
			return bReturn;
		}
		
		private function Swap(a:int, b:int, fSpeed:Number = 200):void{
			
			var upperBlock:Block = BlockArr[a];
			var lowerBlock:Block = BlockArr[b];
			
			//둘 다 없는 경우는 return
			if(!upperBlock.IsActivate() && !lowerBlock.IsActivate()) return;
			
			var vtPos = {x:int(a%BLOCKCOUNT_W)*BLOCK_WIDTH, y:int(a/BLOCKCOUNT_W)*BLOCK_HEIGHT};
			var vtPos1 = {x:int(b%BLOCKCOUNT_W)*BLOCK_WIDTH, y:int(b/BLOCKCOUNT_W)*BLOCK_HEIGHT};
			
			var isActive:Boolean = upperBlock.IsActivate();
			var isActive1:Boolean = lowerBlock.IsActivate();
			
			var BlockColor:int = upperBlock.GetBlockColor();
			var BlockColor1:int = lowerBlock.GetBlockColor();
			
			var BigBlockType:int = upperBlock.GetBigBlockType();
			var BigBlockType1:int = lowerBlock.GetBigBlockType();
			
			var DummyBlock:Boolean = upperBlock.IsDummyBlock();
			var DummyBlock1:Boolean = lowerBlock.IsDummyBlock();
			
			var PinBlock:Boolean = upperBlock.IsPinBlock();
			var PinBlock1:Boolean = lowerBlock.IsPinBlock();
			
			var MagicBlock:Boolean = upperBlock.GetMagicBlock();
			var MagicBlock1:Boolean = lowerBlock.GetMagicBlock();
			
			var ChainBlock:Boolean = upperBlock.GetChainBlock();
			var ChainBlock1:Boolean = lowerBlock.GetChainBlock();
			
			var EraserBlock:Boolean = upperBlock.GetEraserBlock();
			var EraserBlock1:Boolean = lowerBlock.GetEraserBlock();

			var RollOver:Boolean = upperBlock.IsRollOver();
			var RollOver1:Boolean = lowerBlock.IsRollOver();

			
			if(isActive){
				lowerBlock.Activate();
				lowerBlock.SetPos(vtPos);
				lowerBlock.MoveToVertical(vtPos1.y, BLOCK_DROP_SPEED_CURRENT);
				   
				lowerBlock.SetBlockColor(BlockColor);
				lowerBlock.SetBigBlockType(BigBlockType);
				lowerBlock.SetDummyBlock(DummyBlock);
				lowerBlock.SetMagicBlock(MagicBlock);
				lowerBlock.SetPinBlock(PinBlock);
				lowerBlock.SetChainBlock(ChainBlock);
				lowerBlock.SetEraserBlock(EraserBlock);

				if(RollOver)
					lowerBlock.SetRollOver();
				else
					lowerBlock.SetRollOut();
			}else{
				lowerBlock.Deactivate();
				lowerBlock.SetPos(vtPos1);
			}
			
			if(isActive1){
				upperBlock.Activate();
				upperBlock.SetPos(vtPos1);
				upperBlock.MoveToVertical(vtPos.y, BLOCK_DROP_SPEED_CURRENT);
				
				upperBlock.SetBlockColor(BlockColor1);
				upperBlock.SetBigBlockType(BigBlockType1);
				upperBlock.SetDummyBlock(DummyBlock1);
				upperBlock.SetMagicBlock(MagicBlock1);
				upperBlock.SetPinBlock(PinBlock1);
				upperBlock.SetChainBlock(ChainBlock1);
				upperBlock.SetEraserBlock(EraserBlock1);
								
				if(RollOver1)
					upperBlock.SetRollOver();
				else
					upperBlock.SetRollOut();
	
			}else{
				upperBlock.Deactivate();
				upperBlock.SetPos(vtPos);
			}
		}
		
		private function MakeBigBlock():void{
			var nXGrid, nYGrid:int;			
			var pBlock:Block;		
			var pBlock1:Block;
			var pBlock2:Block;
			var bMakeBigBlock:Boolean = false;
			var bMakMakeBlock:Boolean = false;
			
			var i, j, k:int;
			
			
			//이 프레임에서 매직턴이 만들어졌는가? 를 체크해서 false
			
			
			for(j =  BLOCKCOUNT_H-1 ; j > -1 ; j--)
			{
				for(i = 0 ; i < BLOCKCOUNT_W; i ++)
				{
					pBlock1 = GetBlock(i, j);
		
					if(!pBlock1.IsActivate())
						continue;
					
					
					if(pBlock1.IsDummyBlock() || pBlock1.GetBigBlockType() != 0 || pBlock1.IsPinBlock() || pBlock1.GetEraserBlock())
						continue;
		
					for(k = 0 ; k < 3 ; k ++)
					{
						nXGrid = i + ptCheck[k].x;
						nYGrid = j + ptCheck[k].y;
						pBlock = GetBlock(nXGrid, nYGrid);
						if(!pBlock) {
							break;
						}
						if(!pBlock.IsActivate()){
							break;
						}
						if(pBlock.IsDummyBlock() || pBlock.GetBigBlockType() != 0){
							break;
						} else if(pBlock.GetBlockColor() != pBlock1.GetBlockColor()){
							break;
						}
						if(pBlock.IsPinBlock()){
							break;
						}
						if(pBlock.GetEraserBlock()){
							break;
						}
		
					}
		
					if(k == 3)
					{
						pBlock1.SetBigBlockType(4);
						//빅블럭 만들기 효과
						
						pBlock1.BigBlockEffect();
						
						
						
						
						//MagicBlock인지 체크
						if(MagicTurnFlag){
							trace("매직블럭 만들어!!!!!!!!!!");
							//if(MagicMC.currentFrame == 1) MagicMC.play();
							
							//var Effect = new Effect_MagicTurn(pBlock1, pBlock1.GetBlockColor(), 2, -43);
							//Menu_InGame.EffectLevel.addChild(Effect);
							
							bMakMakeBlock = true;
							pBlock1.SetMagicBlock(true);
							
							pBlock1.MagicBlockEffect();
							
						}
						
						if(chainBlockFlag){
							
							
							if(pBlock1.GetBlockColor() != 3 && pBlock1.GetBlockColor() != 4){
								trace("체인블럭 만들어!!!!!!!!!!!");
								pBlock1.SetChainBlock(true);
								pBlock1.ChainBlockEffect();
								
								//var Effect2 = new Effect_Chain(pBlock1, pBlock1.GetBlockColor(), 2, -43);
								//Menu_InGame.EffectLevel.addChild(Effect2);
							}
							
						}
						
						
						for(k = 0 ; k < 3 ; k ++){
							nXGrid = i + ptCheck[k].x;
							nYGrid = j + ptCheck[k].y;
							pBlock2 = GetBlock(nXGrid, nYGrid);
							pBlock2.SetDummyBlock(true);
							bMakeBigBlock = true;
						}
					}
				}
			}
				if(bMakMakeBlock)
					Clickr.snd_MagicTurn.play();
			
		}
		
		
		private function CheckLinkedBlockList():Boolean{
			//BlockLinkCheck 플래그를 false 초기화
			//BlockLinkCheck는 미리 생성해두고 여기서는 0으로 초기화만하기
			var pBlock:Block;
			
			for(var j:int=0; j < BLOCKCOUNT_W * BLOCKCOUNT_H; j++){
				BlockLinkCheck[j] = 0;
				
				pBlock = (BlockArr[j]);
				
				//Block의 연결 Hand를 풀어준다.
				pBlock.SetRightHand(false);
				pBlock.SetBottomHand(false);
				pBlock.DrawLink();
				
			}
			//BlockLinkCheck = new Array(BLOCKCOUNT_W * BLOCKCOUNT_H);
			//LinkColorBlockList 초기화
			LinkColorBlockList.clear();			
			
			var pCheckBlock:Block;
			
			CheckBlockList.clear();
			TempLinkBlockList.clear();
			
			var it:DListIterator;
			
			var nBlockX, nBlockY, nCBlockX, nCBlockY:int;
			var nCheckIndex, nBlockIndex:int;
			
			var bReturn:Boolean = false;
			
			//검색해야 할 BlockIndex 오른쪽, 왼쪽 위, 아래..
			var CIndex:Array = [new Point(1,0),
								new Point(-1,0),
								new Point(0,1),
								new Point(0,-1)]			
			
			var SrcColor:int;
			
			//BlockMap 순환
			for(var i:int = 0 ; i < BLOCKCOUNT_W * BLOCKCOUNT_H ; i ++){
				//BlockLinkCheck 가 되어 있다면 Pass
				//if(BlockLinkCheck[i]) continue;
				
				pBlock = (BlockArr[i]);
				
				if(BlockLinkCheck[i]) continue;
				
				if(pBlock)
				{
					//if(!pBlock.IsActivate()) continue;
		
					SrcColor = pBlock.GetBlockColor();
					if(SrcColor == 3) continue;
					if(SrcColor == 4) continue;
					
					//지우개블럭은 연결안함
					if(pBlock.GetEraserBlock()) continue;
					
					
					if(pBlock.GetBigBlockType() == 0) continue;
		
					nBlockIndex = i;
					//빅블럭이 확인 되면 검사 리스트에 추가한다.
					
					
					//as3ds 에서 append와 prepend의 차이?
					
					//push_back(nBlockIndex);	가장 뒤에 데이터를 넣음
					CheckBlockList.append(nBlockIndex);	//push_back
					
					//임시 연결 리스트에 추가.
					TempLinkBlockList.append(nBlockIndex); //push_back
					
					BlockLinkCheck[nBlockIndex] = 1;
				}else {
					continue;
				}
				
				//검사리스트가 모두 없어질때 까지 순환한다.
				
				while(CheckBlockList.size)
				{
					it = CheckBlockList.getListIterator();
					nBlockX = int(it.data % BLOCKCOUNT_W)
					nBlockY = int(it.data / BLOCKCOUNT_W);
					
					//4방향 검사
					for(var k:int = 0 ; k < 4 ; k ++)
					{
						nCBlockX = nBlockX + CIndex[k].x;
						nCBlockY = nBlockY + CIndex[k].y;
						pCheckBlock = GetBlock(nCBlockX, nCBlockY);
						nCheckIndex = nCBlockX + nCBlockY * BLOCKCOUNT_W;
		
						if(pCheckBlock && !BlockLinkCheck[nCheckIndex])
						{
							if(pCheckBlock.IsActivate())
							{
								if(!pCheckBlock.GetEraserBlock()){
									if(SrcColor == pCheckBlock.GetBlockColor())
									{
										//같은 색깔 블럭이 확인 되면 검사리스트와 임시 연결리스트에 추가한다.
										BlockLinkCheck[nCheckIndex] = 1;
										CheckBlockList.append(nCheckIndex);
										TempLinkBlockList.append(nCheckIndex);
									}
								}
							}
						}
					}
					CheckBlockList.removeHead();
				}
				
				//검사가 끝나면 임시 연결 리스트의 내용을 LinkColorBlockList에 추가해준다.
				it = TempLinkBlockList.getListIterator();
				
				for( ; it.hasNext() ; it.next()){
					LinkColorBlockList.append(it.data);
				}
		
				//LinkblockArray사이를 표식해주기 위해 마디에 -1을 표시해둔다.
				LinkColorBlockList.append(-1);
		
				//연결이 확인된경우 Return값을 true로 변경해준다.
				bReturn = true;
				TempLinkBlockList.clear();
				CheckBlockList.clear();

			}
		
			//풀어놨던 BlockHand를 다시 연결해준다.
			LinkBlockHand();
			
		
			return bReturn;
		}
		
		private function LinkBlockHand():void{
			var it:DListIterator;
			var SrcColor:int;
			var pCheckBlock:Block;
			var nBlockX, nBlockY:int;
			
			
			it = LinkColorBlockList.getListIterator();
			
			for ( ; it.hasNext() ; it.next()) {
				
				
				if (it.data == -1) continue;
				
				SrcColor = BlockArr[it.data].GetBlockColor();
				nBlockX = it.data % BLOCKCOUNT_W;
				nBlockY = it.data / BLOCKCOUNT_W;
				pCheckBlock = GetBlock(nBlockX + 1, nBlockY);
		
				if(pCheckBlock)
				{
					if(pCheckBlock.IsActivate())
					{
						if(!pCheckBlock.GetEraserBlock())
						{
							if(pCheckBlock && SrcColor == pCheckBlock.GetBlockColor())
							{
								BlockArr[it.data].SetRightHand(true);
								
							}
						}
					}
				}
				BlockArr[it.data].DrawLink();
				pCheckBlock = GetBlock(nBlockX, nBlockY + 1);
				if(pCheckBlock)
				{
					if(pCheckBlock.IsActivate())
					{
						if(!pCheckBlock.GetEraserBlock())
						{
							if(pCheckBlock && SrcColor == pCheckBlock.GetBlockColor())
							{
								BlockArr[it.data].SetBottomHand(true);
							}
							
						}
					}
				}
				BlockArr[it.data].DrawLink();
			}
		}
		
		
		private function OnMouseMove(e:MouseEvent):void{
			//마우스 위치가 블럭
			
			var nBlockPosX:int = int((e.stageX - this.x) / BLOCK_WIDTH);
			var nBlockPosY:int = int((e.stageY - this.y) / BLOCK_HEIGHT);
			
			
			if(nBlockPosX != prevMouseX || nBlockPosY != prevMouseY){
				OnMouseOut(prevMouseX, prevMouseY);
				OnMouseOver(nBlockPosX, nBlockPosY);
				
				prevMouseX = nBlockPosX;
				prevMouseY = nBlockPosY;

			}
		}
		
		private function OnMouseMoveIn(e:MouseEvent):void{
			//마우스 위치가 블럭
			//trace("MoveIn");
			var nBlockPosX:int = int((e.stageX - this.x) / BLOCK_WIDTH);
			var nBlockPosY:int = int((e.stageY - this.y) / BLOCK_HEIGHT);
			
			OnMouseOver(nBlockPosX, nBlockPosY);
				
			prevMouseX = nBlockPosX;
			prevMouseY = nBlockPosY;
		}
		
		private function OnMouseMoveOut(e:MouseEvent):void{
			//마우스 위치가 블럭
			//trace("MoveOut");
			var nBlockPosX:int = int((e.stageX - this.x) / BLOCK_WIDTH);
			var nBlockPosY:int = int((e.stageY - this.y) / BLOCK_HEIGHT);
			
			OnMouseOut(prevMouseX, prevMouseY);
				
			prevMouseX = nBlockPosX;
			prevMouseY = nBlockPosY;
		}
		
		
		private function OnMouseOver(nX:int, nY:int):void{
			
			if(IsBlockMoving()) return;
			
			if(IsBlockMovingRotation()) return;
			
			
			var ptMouse:Point = FindParent(nX, nY);
			
			var pBlock:Block = GetBlock(ptMouse.x, ptMouse.y);
			
			
			if(!pBlock) return;
				
			if(!pBlock.IsActivate()) return;
			
			
			var nType:int = pBlock.GetBigBlockType();
			var nColor:int = pBlock.GetBlockColor();
			//if(nType == 0)
			if(nType == 0)
			{
				switch(nColor)
				{
				case 0:
				case 1:
				case 2:
					{
						OnMouseOverNormalBlock(pBlock);
					}break;
				case 3:
					OnMouseOverStarBlock(pBlock, nX, nY);
					break;
					
				case 4:
					{
						//OnMouseOverStoneBlock(ptMouse.x, ptMouse.y);
					}break;
				}
			}
			else
			{
				switch(nColor)
				{
				case 0:
				case 1:
				case 2:
					//if(!pBlock.IsRollOver()) 
					OnMouseOverBigBlock(ptMouse.x, ptMouse.y);
					break;
				case 3:
					{
						OnMouseOverNormalBlock(pBlock);
					}break;
				case 4:
					{
						//OnMouseOverBigStone(ptMouse.x, ptMouse.y);
					}break;
				}
			}
		}
		
		private function OnMouseOverNormalBlock(pBlock:Block):void{
			
			if(pBlock.GetEraserBlock()){
				for(var i in BlockArr){
					//지우개랑 같은색 블럭은 롤오버
					if(BlockArr[i].GetEraserBlock() && BlockArr[i] != pBlock) continue;
					
					if(pBlock.GetBlockColor() == BlockArr[i].GetBlockColor()){
						BlockArr[i].SetRollOver();
					}
				}
			}else if (pBlock.IsPinBlock()) {
				trace("핀블럭은 스킵");
				
				
			}else {
				pBlock.SetRollOver();
			}
		}
		
		//OnMouseOutStarBlock 따로 만들어야 할 듯
		private function OnMouseOverStarBlock(pBlock:Block, nX:int, nY:int):void{
			
			
			FindChangeStarBlockColor(nY * BLOCKCOUNT_W + nX);
			
			pBlock.SetRollOverStar(pChangeColor);
		}
		
		private function OnMouseOutStarBlock(pBlock:Block){
			
			pBlock.SetRollOut();
		}
		
		
		private function OnMouseOverBigBlock(nX:int, nY:int):void{
			//trace("MouseOver Big Block");
			
			var nBlockIndex:int = nX + nY * BLOCKCOUNT_W;
			
			var pBlock:Block;
			
			var it:DListIterator = LinkColorBlockList.getListIterator();
			
			var itMarkStart:DListIterator = LinkColorBlockList.getListIterator();
			
			var pinLinked = false;
			
			for ( ; it.hasNext() ; it.next()) {
				
				//List의 시작점을 저장해준다.
				if(it.data == "-1"){
										
					itMarkStart.node = it.node;
					itMarkStart.next();
					
				}
				if(nBlockIndex == it.data)
					break;
			}
			
			it = itMarkStart;
			
			for( ; it.hasNext() ; it.next()){
				if(it.data == "-1")
					break;

				pBlock = BlockArr[it.data];
				if(!pBlock.IsActivate()) return;
				
				if(pBlock.IsPinBlock() && pBlock.IsActivate()){
					pinLinked = true;
				}
				
				
				pBlock.SetRollOver();
				
			}
			
			if(pinLinked) GUI_Cursor.cursor.setCursor(1);
			
		}
		
		private function OnMouseOut(nX:int, nY:int):void{
			
			if(IsBlockMoving()) return;
			
			if(IsBlockMovingRotation()) return;
			
			
			
			var ptMouse:Point = FindParent(nX, nY);
			
			var pBlock:Block = GetBlock(ptMouse.x, ptMouse.y);
			
			if(!pBlock) return;
			
			if(!pBlock.IsActivate()) return;
			
			
			
			var nType:int = pBlock.GetBigBlockType();
			var nColor:int = pBlock.GetBlockColor();
			//if(nType == 0)
			if(nType == 0)
			{
				switch(nColor)
				{
				case 0:
				case 1:
				case 2:
				OnMouseOutNormalBlock(pBlock);
				break;
				case 3:
				OnMouseOutStarBlock(pBlock);
				break;
				case 4:
					{
						//OnMouseOutStoneBlock(ptMouse.x, ptMouse.y);
					}break;
				}
			}
			else
			{
				switch(nColor)
				{
				case 0:
				case 1:
				case 2:
					{	
					
					//같은 빅블럭 내에서 ptMouse위치 변화했다면 (다른 블럭에 rollOver했다면) return
						OnMouseOutBigBlock(ptMouse.x, ptMouse.y);
					}break;
				case 3:
					{
						OnMouseOutNormalBlock(pBlock);
					}break;
				case 4:
					{
						//OnMouseOutBigStone(ptMouse.x, ptMouse.y);
					}break;
				}
			}
		}
		
		private function OnMouseOutNormalBlock(pBlock:Block):void{
			
			if(pBlock.GetEraserBlock()){
				for(var i in BlockArr){
					if(BlockArr[i].GetEraserBlock() && BlockArr[i] != pBlock) continue;
					
					if(pBlock.GetBlockColor() == BlockArr[i].GetBlockColor()){
						BlockArr[i].SetRollOut();
					}
				}
			}else{
				pBlock.SetRollOut();
			}
			
			
		}
		
		private function OnMouseOutBigBlock(nX:int, nY:int):void{
			//trace("MouseOut Big Block");
			
			var nBlockIndex:int = nX + nY * BLOCKCOUNT_W;
			
			var pBlock:Block;
			
			var it:DListIterator = LinkColorBlockList.getListIterator();
			
			var itMarkStart:DListIterator = LinkColorBlockList.getListIterator();
			
			for ( ; it.hasNext() ; it.next()) {
				
				//List의 시작점을 저장해준다.
				if(it.data == "-1"){
										
					itMarkStart.node = it.node;
					itMarkStart.next();
					
				}
				if(nBlockIndex == it.data)
					break;
			}
			
			it = itMarkStart;
			
			for( ; it.hasNext() ; it.next()){
				if(it.data == "-1")
					break;

				pBlock = BlockArr[it.data];
				if(!pBlock.IsActivate()) return;
				
				
				pBlock.SetRollOut();
			}
			
			//더블찬스가 아니면 원래 상태로
			if(!(currentCombo % 10 == 0 && currentCombo != 0)){
				GUI_Cursor.cursor.setCursor(0);
			}
		}
		
		
		
		private function OnMouseDown(e:MouseEvent, _ptX=0, _ptY=0):void{
			//trace("MD");
			//이벤트 페이즈 들어가야겠으
			
			if(IsBlockMoving()) return;
			
			if(IsBlockMovingRotation()) return;
			
			willMakePin = true;
			
			MagicTurnFlag = false;	//매직블럭 unavailable
			chainBlockFlag = false;
			
			var nBlockPosX:int;
			var nBlockPosY:int;
			
			if(_ptX == 0 && _ptY == 0){
				nBlockPosX = int((e.stageX - this.x) / BLOCK_WIDTH);
				nBlockPosY = int((e.stageY - this.y) / BLOCK_HEIGHT);
			}else{
				nBlockPosX = int(_ptX / BLOCK_WIDTH)
				nBlockPosY = int(_ptY / BLOCK_HEIGHT)
			}
			
			var ptMouse:Point = FindParent(nBlockPosX, nBlockPosY);
			
			var pBlock:Block = GetBlock(ptMouse.x, ptMouse.y);
			//trace("pBlock", pBlock);
			
			if(!pBlock) return;
				
			var nType:int = pBlock.GetBigBlockType();
			var nColor:int = pBlock.GetBlockColor();
			
			if(nType == 0){
				switch(nColor){
				case 0:
				case 1:
				case 2:
				OnMouseDownNormalBlock(ptMouse.x, ptMouse.y);
				break;
				case 3:
				OnMouseDownStarBlock(ptMouse.x, ptMouse.y);
				break;
				case 4:
				OnMouseDownStoneBlock(ptMouse.x, ptMouse.y);
				break;
				}
			}else{
				switch(nColor){
				case 0:
				case 1:
				case 2:
				chainBlockFlag = true;
				OnMouseDownBigBlock(ptMouse.x, ptMouse.y, pBlock);
				break;
				case 3:
				OnMouseDownBigStar(ptMouse.x, ptMouse.y);
				break;
				case 4:
				
				break;
				}
			}
		}
		
		private function OnMouseDownBigBlock(nX:int, nY:int, clickedBlock:Block):void{
			var nBlockIndex:int = nX + nY * BLOCKCOUNT_W;
			var pBlock:Block;
			var it:DListIterator = LinkColorBlockList.getListIterator();
			var itMarkStart:DListIterator = LinkColorBlockList.getListIterator();
			loseBlockCnt = 0;
			trace("onMouseDown Big Block");
			
			var S = 0
			var K = 20;
			var B = 0
			var M = 2.5;
			var ChainBlocks = 0;
			var MagicBlocks = 0;
			
			var pinLinked = false;
			var doubleChanced:int = 1;
			
			
			for ( ; it.hasNext() ; it.next()) {
				if(it.data == "-1"){
					itMarkStart.node = it.node;
					itMarkStart.next();
				}
				if(nBlockIndex == it.data)
					break;
			}
			
			//Block_B_S_Remove2
			
			
			
			
			//List의 시작점 부터 다음 리스트 시작점 까지.. 지워준다.
			it = itMarkStart;
			for( ; it.hasNext() ; it.next()){
				if(it.data == "-1")
					break;

				pBlock = BlockArr[it.data];
				var currentColor = pBlock.GetBlockColor();
				if(!pBlock.IsActivate()) return;
				
				//여기서 하면 안됨... 여러 번 호출되면 안됨..
				//지워준게 핀블럭이면 
				if(pBlock.IsPinBlock() && pBlock.IsActivate()){
					trace("핀블럭 재설정 예약");
					//해당 핀블럭이 현재 없음
						
					PointPinBlocks[pBlock.GetBlockColor()] = false;
					pinLinked = true;
				}
				
				if(pBlock.GetChainBlock()) ChainBlocks++;
				
				if(pBlock.GetMagicBlock()) MagicBlocks++;
				
				
				//노말블럭이면
				if(pBlock.GetBigBlockType() == 0 && !pBlock.IsDummyBlock()) {
					S++;					
				}
				
				//빅블럭이면
				if(pBlock.GetBigBlockType() != 0) {
					B++;					
				}
				
				
				//핀블럭이 지워지는 경우. 
				//1 - 빅블럭과 연결되있을 경우
				//2 - star를 통해 리셋됐을 경우
				//3 - 지우개를 통해 지웠을 경우
				
				pBlock.SetRightHand(false);
				pBlock.SetBottomHand(false);
				pBlock.DrawLink();
				
				loseBlockCnt++;
				
				//pBlock.Deactivate();
				
				
			}
			
			BLOCK_DROP_SPEED_CURRENT = BLOCK_DROP_SPEED + loseBlockCnt * 10;
			
			trace("S : " + S); trace("B : " + B); trace("ChainBlocks", ChainBlocks); trace("MagicBlocks", MagicBlocks);
			
			if (B >= 5) {
				EraserFlag[0] = true	//조건 3
				
			}
			
			currentCombo++;
			//콤보 올라가는 효과 addChild
			if(currentCombo > 1){
				dispatchEvent(new CustomEvent(CustomEvent.COMBO_PLUS));
			}
			
			
			var upScore:Number;
			
			//핀블럭이랑 연결됐을 때만 핀블럭 보너스
			if (pinLinked) {
				EraserFlag[1]++;
				if(EraserFlag[1] >= 3){
					trace("지우개 조건2 생성");
					EraserFlag[0] = true;
					EraserFlag[1] = 0;	//조건 2 초기화
				}				
				upScore = Math.floor(((((S + K * B)*(B+M) * calcComboBonus(currentCombo)) + 10 * ChainBlocks) * (MagicBlocks + 1)) * PointPinMultiRate[PointPinIndexArray[currentColor]]) * doubleChanced;
			}else {
				EraserFlag[1] = 0;
				
				upScore = Math.floor((((S + K * B)*(B+M) * calcComboBonus(currentCombo)) + 10 * ChainBlocks) * (MagicBlocks + 1)) * doubleChanced;
			}
			//trace("pinLinked", pinLinked);
			
			SCORE += upScore;
			//Menu_InGame에서 또르륵 올라가게
			
			
			trace("upScore : " + upScore);
			trace("SCORE : " + SCORE);
			
			Menu_InGame.UI.dispatchEvent(new CustomEvent(CustomEvent.SCORE_UP, upScore));
			GUI_Cursor.cursor.setCursor(0);
			
			
			
			it = LinkColorBlockList.getListIterator();
			itMarkStart = LinkColorBlockList.getListIterator();
			
			for ( ; it.hasNext() ; it.next()) {
				if(it.data == "-1"){
					itMarkStart.node = it.node;
					itMarkStart.next();
				}
				if(nBlockIndex == it.data)
					break;
			}
			
			it = itMarkStart;
			for( ; it.hasNext() ; it.next()){
				if(it.data == "-1")
					break;
				
				
				pBlock = BlockArr[it.data];
				if (!pBlock.IsActivate()) return;
				
				
				//크게 터져라
				if (upScore >= 50000) {
					pBlock.dispatchEvent(new CustomEvent(CustomEvent.REMOVE_BLOCK_BIG, 0, Menu_InGame.EffectLevel));
					
					
				}else {
					pBlock.dispatchEvent(new CustomEvent(CustomEvent.REMOVE_BLOCK, 0, Menu_InGame.EffectLevel));
					
					
				}
				pBlock.Deactivate();
			}
			
			var blockPoint = new BlockPoint(upScore, clickedBlock.GetBlockColor());
			
			blockPoint.x = clickedBlock.x + BLOCK_WIDTH + 250;
			blockPoint.y = clickedBlock.y + 25;
			Menu_InGame.EffectLevel.addChild(blockPoint);
			
			
			if(currentCombo % 10 == 0){
				Clickr.snd_DoubleChance.play();
								
				//Menu_InGame에 DoubleChance dispatchEvent
				dispatchEvent(new CustomEvent(CustomEvent.DOUBLE_CHANCE_START));
				
			//10x + 1이면 || MagicBlocks가 1 이상이면 Double 
			}else if((currentCombo % 10 == 1 && currentCombo != 1) || MagicBlocks >= 1){
				Clickr.snd_Double.play();
				GUI_Cursor.cursor.setCursor(0);
				//더블찬스 시작 경우와 MagicCombo 경우 분리
				
				if(currentCombo % 10 == 1 && currentCombo != 1) {
					dispatchEvent(new CustomEvent(CustomEvent.DOUBLE_CHANCE_SUCCESS));
					doubleChanced = 2;
				}
				
			}else if(pinLinked && PointPinMultiRate[PointPinIndexArray[currentColor]] > 10){
				Clickr.snd_PC_AllClearNN.play();
			}else if(pinLinked){
				Clickr.snd_PC_AllClearN.play();
			}else{
				Clickr.snd_AllClear.play();
			}
		}
		
		
		private function OnMouseDownNormalBlock(nX:int, nY:int):void{
			var clicklossPlayed:Boolean = false;
			
			//trace("onMouseDown Normal Block");
			var pBlock:Block = GetBlock(nX, nY);
			
			if(pBlock.IsPinBlock()) return;
			
			if(!pBlock.IsActivate()) return;
						
			//콤보 리셋 - 지우개 블럭은 예외			
			if(!pBlock.GetEraserBlock()){
				if(currentCombo % 10 == 0 && currentCombo != 0){
					Clickr.snd_Clickloss.play();
					clicklossPlayed = true;
					dispatchEvent(new CustomEvent(CustomEvent.DOUBLE_CHANCE_FAIL));
					
				}
				currentCombo = 0;
				//콤보창 리셋
				
				EraserFlag[1] = 0;
			}
			
			
			BLOCK_DROP_SPEED_CURRENT = BLOCK_DROP_SPEED;
			
			
			//지우개블럭을 지워줬으면
			if(pBlock.GetEraserBlock()) {
				trace("Cleared Eraser Block");
				ClearAllColor(pBlock.GetBlockColor(), pBlock);
				Clickr.snd_EraseBlockUse.play();
				
				//같은 색의 블럭 모두 지우기 효과 (지우개 블럭 뺴고)
				for(var i in BlockArr){
					if(BlockArr[i].GetEraserBlock() && BlockArr[i] != pBlock) continue;
					
					
					if(pBlock.GetBlockColor() == BlockArr[i].GetBlockColor()){
						
						pBlock.dispatchEvent(new CustomEvent(CustomEvent.REMOVE_ERASER));
						
					}
				}
				
				
				
				
				
			}else {
				
				pBlock.dispatchEvent(new CustomEvent(CustomEvent.REMOVE_BLOCK));
				
				//다른 소리가 안나왔을 때만 기본 클릭소리 플레이.
				if (!clicklossPlayed) Clickr.snd_Click.play();
				
			}
			
			
			
			
			pBlock.Deactivate();
		}
		
		
		public function kill(e:CustomEvent) {
			trace("klill called");
			
			e.obj.parent.removeChild(e.obj);
			
		}
		
		private function OnMouseDownStarBlock(nX:int, nY:int):void{
			trace("onMouseDown Star Block");
			var pBlock:Block = GetBlock(nX, nY);
			
			FindChangeStarBlockColor(nY * BLOCKCOUNT_W + nX);
			
			pBlock.SetBlockColor(pChangeColor);
			
			Clickr.snd_ClickSmallStar.play();
			
			pBlock.dispatchEvent(new CustomEvent(CustomEvent.REMOVE_STAR));
			
		}
		
		
		
		
		private function OnMouseDownStoneBlock(nX:int, nY:int):void{
			
		}
		
		private function OnMouseDownBigStar(nX:int, nY:int):void{
			//BigStar가 여러개 있으면 그것만큼 여러번 돌아줘야함
			//돌때마다 점수 계속 줘야되는거임?
			bigStarFlag = true;
			LeftBigStarCount = 0;

			for(var i = 0 ; i < BLOCKCOUNT_W * BLOCKCOUNT_H ; i ++){
				
				//BlockArr[i].SetRightHand(false);
				//BlockArr[i].SetBottomHand(false);				
				//BlockArr[i].DrawLink();
						
				if(BlockArr[i].GetBigBlockType() != 0){
					if(BlockArr[i].GetBlockColor() == 3){
						LeftBigStarCount++;
						
						
				
						if(BlockArr[i].GetMagicBlock()){
							LeftBigStarCount++;
						}						
					}
				}
			}
			
			trace("왕별 클리어 point index 증가 예약");
			PointPinBlocks[0] = false;
			PointPinBlocks[1] = false;
			PointPinBlocks[2] = false;
			
			ClearAllMap();
			
			
			var upScore:Number = 100 * (LeftBigStarCount+1);
			
			SCORE += upScore;
			
			trace("upScore : " + upScore);
			trace("SCORE : " + SCORE);
			
			//Menu_InGame.UI.dispatchEvent(new CustomEvent(CustomEvent.SCORE_UP, upScore));
			
		}
		
		private function ClearAllMap(){
			trace("ClearAllMap called");
			
			for(var i = 0 ; i < BLOCKCOUNT_W * BLOCKCOUNT_H ; i ++){
				if (BlockArr[i].IsActivate()) {
					BlockArr[i].dispatchEvent(new CustomEvent(CustomEvent.REMOVE_BLOCK_BIG, 0, Menu_InGame.EffectLevel));
					
					BlockArr[i].Deactivate();
				}
			}
			BLOCK_DROP_SPEED_CURRENT = BLOCK_DROP_SPEED;
			LeftBigStarCount--;	//호출될 때마다 --
			
			if(LeftBigStarCount == 0){
				Clickr.snd_BigStarLast.play();
			}else{
				Clickr.snd_BigStar.play();
			}
			EraserFlag[0] = true;
			
			
			//점수 ++
			
			
			return;
		}
		
		//한가지 색을 모두 지워줌
		private function ClearAllColor(_color:int, pBlock:Block){
			trace("ClearAllColor called");
			EraserBlocks[_color] = false;
			PointPinBlocks[_color] = false;
			EraserBonusFlag = true;
			
			for (var i = 0 ; i < BLOCKCOUNT_W * BLOCKCOUNT_H ; i ++) {
				
				if (BlockArr[i].IsActivate()) {
					
					//호출자가 아닌 지우개 블럭은 안지움
					if(BlockArr[i].GetEraserBlock() && BlockArr[i] != pBlock) continue;
					
					
					if (BlockArr[i].GetBlockColor() == _color) {
						BlockArr[i].dispatchEvent(new CustomEvent(CustomEvent.REMOVE_ERASER, 0, Menu_InGame.EffectLevel));
						
						BlockArr[i].Deactivate();
					}
				}
			}
			
			BLOCK_DROP_SPEED_CURRENT = BLOCK_DROP_SPEED;
						
			return;
		}
		
		
		private function FindParent(nX:int, nY:int):Point{
			var pBlock:Block = GetBlock(nX, nY);
			var pBlock1:Block;
			
			var ptReturn:Point = new Point(nX, nY);
			
			var ptTemp:Array = [
								new Point(-1,-1), new Point(0,-1), new Point(1,-1),
								new Point(-1,0), 				new Point(1,0),
								new Point(-1,1), new Point(0,1), new Point(1,1)
								];
			
			var nCheckPos:Array = [
								   [0, 0, 0],
								   [0, 1, 3],
								   [1, 2, 4],
								   [4, 6, 7],
								   [5, 6, 3]
								   ];
			
			var nType:int;
			for(var i:int = 0 ; i < 8 ; i ++)
			{
				pBlock1 = GetBlock(nX + ptTemp[i].x, nY + ptTemp[i].y);
				if(!pBlock1 || !pBlock1.IsActivate()) continue;
				
				
				nType = pBlock1.GetBigBlockType();
				if(nType == 0) continue;
					
				for(var j:int = 0 ; j < 3 ; j ++)
				{
					if(i == nCheckPos[nType][j])
					{
						ptReturn.x = nX + ptTemp[i].x;
						ptReturn.y = nY + ptTemp[i].y;
						return ptReturn;
					}
				}
			}
		
			return ptReturn;
		}
		
		
		private function GetBlock(xPos:int, yPos:int):Block{
			if(xPos < 0 || xPos >= BLOCKCOUNT_W) return null;			
			if(yPos < 0 || yPos >= BLOCKCOUNT_H) return null;
			return BlockArr[xPos + yPos * BLOCKCOUNT_W];
		}
		
		public function MultiMat(m1:Matrix, m2:Matrix):Matrix{
			var resultMat:Matrix = new Matrix();
			
			resultMat.a = m1.a*m2.a		+	m1.b*m2.c;
			resultMat.b = m1.a*m2.b		+	m1.b*m2.d;
			resultMat.tx = m1.a*m2.tx	+	m1.b*m2.ty	+	m1.tx;
			resultMat.c = m1.c*m2.a		+	m1.d*m2.c;
			resultMat.d = m1.c*m2.b		+	m1.d*m2.d;
			resultMat.ty = m1.c*m2.tx	+	m1.d*m2.ty	+	m1.ty;
			
			//trace(resultMat.a, resultMat.b, resultMat.tx);
			//trace(resultMat.c, resultMat.d, resultMat.ty);
			
			return resultMat;
		}
		
		//StarBlock 이 빅블록이 가능 하다면 true를 반환 한다.
		function FindChangeStarBlockColor(nBlockIndex:int):Boolean{
			//스타블럭 가능여부 Boolean 으로 return
			//바뀔 수 있으면 바뀌는 색을 pChangeColor로 return (또는 assign)
			pChangeColor = 0;
			
			var i, j:int;
			
			var pBlock:Block = BlockArr[nBlockIndex];
		
			var nXGrid:int = nBlockIndex % BLOCKCOUNT_W;
			var nYGrid:int = nBlockIndex / BLOCKCOUNT_W;
			
			for(j=0; j < BLOCKCOUNT_W * BLOCKCOUNT_H; j++){
				BlockLinkCheck[j] = 0;
			}
			
			var pCheckBlock0:Block;
			var pCheckBlock1:Block;
			var pCheckBlock2:Block;
			
			
		
			var nBlockColor0, nBlockColor1 , nBlockColor2:int;
			var nStarCount:Array = [-1, -1, -1, -1];
			var nFindBlockColor:Array = [-1, -1, -1, -1];
			
			
			var CBigIndex:Array = [
									[new Point(0,-1), new Point(-1,-1), new Point(-1,0)],
									[new Point(0,-1), new Point(1,-1), new Point(1,0)],
									[new Point(-1,0), new Point(0,1), new Point(-1,1)],
									[new Point(1,0), new Point(0,1), new Point(1,1)]
									];
			
			//Big 블럭이 되는 색이 있으면 star 를 해당 색으로 변경
			for(i = 0 ; i < 4 ; i++)
			{
				pCheckBlock0 = GetBlock(nXGrid + CBigIndex[i][0].x, nYGrid + CBigIndex[i][0].y);
				pCheckBlock1 = GetBlock(nXGrid + CBigIndex[i][1].x, nYGrid + CBigIndex[i][1].y);
				pCheckBlock2 = GetBlock(nXGrid + CBigIndex[i][2].x, nYGrid + CBigIndex[i][2].y);
				
				if(pCheckBlock0 && pCheckBlock2 && pCheckBlock1)
				{
					if(pCheckBlock0.GetBigBlockType() == 0 &&
						pCheckBlock1.GetBigBlockType() == 0 &&
						pCheckBlock2.GetBigBlockType() == 0)
					{
						if(!pCheckBlock0.IsDummyBlock() &&
							!pCheckBlock1.IsDummyBlock() &&
							!pCheckBlock2.IsDummyBlock())
						{
							nBlockColor0 = pCheckBlock0.GetBlockColor();
							nBlockColor1 = pCheckBlock1.GetBlockColor();
							nBlockColor2 = pCheckBlock2.GetBlockColor();
							
							if(pCheckBlock0.IsPinBlock() ||
								pCheckBlock1.IsPinBlock() ||
								pCheckBlock2.IsPinBlock() )
								continue;
		
							if(nBlockColor0 == 4 || nBlockColor1 == 4 || nBlockColor2== 4) continue;
							
		
							if(nBlockColor0 != 3)
							{
								if( ( nBlockColor0 == nBlockColor1 || nBlockColor1 == 3)
									&& ( nBlockColor0 == nBlockColor2 || nBlockColor2 == 3 ) )
								{
									if(nBlockColor0 < 5 || nBlockColor0 == 3)
									{
										nFindBlockColor[i] = nBlockColor0;
									}
								}
							}
							else if(nBlockColor1 != 3)
							{
								if( nBlockColor1 == nBlockColor2 || nBlockColor2 == 3)
								{
									if(nBlockColor0 < 5 || nBlockColor0 == 3)
									{
										nFindBlockColor[i] = nBlockColor1;
									}
								}
							}
							else if(nBlockColor2 != 3)
							{
								nFindBlockColor[i] = nBlockColor1;
							}
		
							if(nFindBlockColor[i] != -1)
							{
								nStarCount[i] = 0;
								if(nBlockColor0 == 3)
									nStarCount[i]++;
								if(nBlockColor1 == 3)
									nStarCount[i]++;
								if(nBlockColor2 == 3)
									nStarCount[i]++;
							}
						}
					}
				}
			}
		
			var nReturnBlock:int = -1;
			var nReturnBlockStarCount:int = 100;
		
			for(j = 0 ; j < 4 ; j ++)
			{
				if(nFindBlockColor[j] != -1)
				{
					if(nReturnBlockStarCount > nStarCount[j])
					{
						nReturnBlock = nFindBlockColor[j];
						nReturnBlockStarCount = nStarCount[j];
					}
				}
			}
		
			if(nReturnBlock != -1 && nReturnBlock != 3)
			{
				
				pChangeColor = nReturnBlock;
				//pChangeColor를 멤버변수로. 여기서 설명.
				
				
				return true;
			}
		
			//현재 연결 되어 있는 블럭 리스트중 가장 큰 연쇄로 변경한다.
			
			
			var CIndex:Array = [new Point(1,0), new Point(-1,0), new Point(0,1), new Point(0,-1)];
			
		
			//Big Block 을 만들수 있는 색이 없다면 현재 배열에서 가장 큰 연쇄를 낼수 있는 색으로 변경한다.
		
			var nBigStreamCount:int;
			
			
			//[nChain, nChainCount, nCount];			
			var ChangeCount:Array = [[0,0,0], [0,0,0], [0,0,0]];
			
			for(i = 0 ; i < 4 ; i++)
			{
				pCheckBlock0 = GetBlock(nXGrid + CIndex[i].x, nYGrid + CIndex[i].y);
				if(pCheckBlock0)
				{
					//			
					if(3 > pCheckBlock0.GetBlockColor())
					{
						nBigStreamCount = FindBigBlockStream(nXGrid + CIndex[i].x, nYGrid + CIndex[i].y);
						ChangeCount[pCheckBlock0.GetBlockColor()][2]++;
						if(nBigStreamCount > 0)
						{
							ChangeCount[pCheckBlock0.GetBlockColor()][0] += nBigStreamCount;
							ChangeCount[pCheckBlock0.GetBlockColor()][1]++;
						}
					}
				}
			}
		
			var nSelectColor:int = 2;
		
			for(var k:int = 0 ; k < 3; k++)
			{
				if(ChangeCount[nSelectColor][1] < ChangeCount[k][1])
				{
					nSelectColor = k;
				}
				else if(ChangeCount[nSelectColor][1] == ChangeCount[k][1])
				{
					if(ChangeCount[nSelectColor][2] < ChangeCount[k][2])
						nSelectColor = k;
					else if(ChangeCount[nSelectColor][2] == ChangeCount[k][2])
					{
						if(ChangeCount[nSelectColor][0] < ChangeCount[k][0])
							nSelectColor = k;
					}
				}
			}
			
			pChangeColor = nSelectColor;
			
			return false;
		}
		
		
		
		
		function FindBigBlockStream(X:int, Y:int):int{
			var it:DListIterator = LinkColorBlockList.getListIterator();
			
			if(LinkColorBlockList.size == 0)
				return 0;
		
			var fAddCount:Number = 1;
		
			var nSrcBlockColor:int = 0;
			var nBlockOrder:int = 0;
			var nBlockOrder2:int = 0;
			var nBlockPos:int = X + Y * 8;
		
			var nClearCount:int = 0; 
			var nBigBlockcount:int = 0; 
			var nBigBlockMultiBouns:int = 0;
			var nAddBlockClearBouns:int = 0;
			
			
			
			for( ; it.hasNext() ; it.next()){
				if (it.data == -1){
					nBlockOrder++;
				}
				if(it.data == nBlockPos)
					break;
			}
			
			it = LinkColorBlockList.getListIterator();
			for( ; it.hasNext() ; it.next()){
				if (it.data == -1)
				{
					nBlockOrder2++;
					it.next();
				}
				if(nBlockOrder == nBlockOrder2)
				{
					break;
				}
		
			}
		
			//	m_nMultiBlockClearBouns = 1;
			//	m_nAddBlockClearBouns = 0;
			//	m_nHighLightBlockPos = -1;
			
			for( ; it.hasNext() ; ){
				if(it.data == -1)
				{
					break;
				}
		
				nSrcBlockColor = BlockArr[it.data].GetBlockColor() - 1;
				
				//		BlockArr[it.data].OnMouseOver();
		
				nClearCount ++;
				if(BlockArr[it.data].GetBigBlockType() != 0)
				{
					nBigBlockcount ++;
					if(BlockArr[it.data].GetMagicBlock())
						nBigBlockMultiBouns++;
					if(BlockArr[it.data].GetChainBlock())
						nAddBlockClearBouns++;
		
					if(BlockArr[it.data].GetBigBlockType() == 1)
					{
						if(nBlockPos == it.data ||
							nBlockPos == it.data + 8 + 1||
							nBlockPos == it.data + 8||
							nBlockPos == it.data + 1)
		
							m_nHighLightBlockPos = it.data;
					}
					else if(BlockArr[it.data].GetBigBlockType() == 2)
					{
						if(nBlockPos == it.data ||
							nBlockPos == it.data + 8 - 1||
							nBlockPos == it.data + 8||
							nBlockPos == it.data - 1)
		
							m_nHighLightBlockPos = it.data - 1;
					}
					else if(BlockArr[it.data].GetBigBlockType() == 3)
					{
						if(nBlockPos == it.data ||
							nBlockPos == it.data - 8 - 1||
							nBlockPos == it.data - 8||
							nBlockPos == it.data - 1)
		
							m_nHighLightBlockPos = it.data - 8 - 1;
					}
					else if(BlockArr[it.data].GetBigBlockType() == 4)
					{
						if(nBlockPos == it.data ||
							nBlockPos == it.data - 8 + 1||
							nBlockPos == it.data - 8||
							nBlockPos == it.data + 1)
		
							m_nHighLightBlockPos = it.data - 8;
					}
		
				}
		
				it.next();
			}
		
			var nBigBlockHLCount:int = nBigBlockcount;
			var nBlockHLCount:int = nClearCount - 3 * nBigBlockcount;
		
			var nMultiBlockClearBouns:int = 1;
		
			for(var i:int = 0 ; i < nBigBlockMultiBouns ; i++)
				nMultiBlockClearBouns *= 2;
		
			nAddBlockClearBouns = nAddBlockClearBouns * 10;
			nMultiBlockClearBouns = min(64, nMultiBlockClearBouns);
		
			var nAddBlock:int = 1;
			
			
			
			nAddBlock = (int)((nBlockHLCount + 20 * nBigBlockHLCount - nBigBlockHLCount) * (nBigBlockHLCount + 2.5) * calcComboBonus(currentCombo));
			
			return (nAddBlock + nAddBlockClearBouns) * nMultiBlockClearBouns;
		}
		
		public static function calcComboBonus(_currentCombo:int):Number{
			var fReturn:Number;
			if(_currentCombo < 20){
				fReturn = ComboBonus[currentCombo];
			}else{
				fReturn = 5;
			}			
			return fReturn;
		}
		
		private function min(_a:Number, _b:Number):Number{
			if(_a > _b){
				return _b;
			}else {
				return _a;
			}
		}


	}
}
